"""
测试模块
包含对主要功能的单元测试
"""
from django.test import TestCase
from django.urls import reverse
from rest_framework.test import APIClient
from rest_framework import status
from .models import User, Category, Novel, Chapter, Bookshelf, AuthorApplication
import json


class UserTests(TestCase):
    """用户相关功能测试"""

    def setUp(self):
        """测试前准备工作"""
        self.client = APIClient()
        # 创建测试用户
        self.admin_user = User.objects.create_superuser(
            username='admin',
            email='admin@example.com',
            password='adminpassword'
        )
        self.reader_user = User.objects.create_user(
            username='reader',
            email='reader@example.com',
            password='readerpassword',
            role='reader'
        )
        self.author_user = User.objects.create_user(
            username='author',
            email='author@example.com',
            password='authorpassword',
            role='author'
        )

    def test_user_registration(self):
        """测试用户注册"""
        url = reverse('user-list')
        data = {
            'username': 'newuser',
            'email': 'newuser@example.com',
            'password': 'newuserpassword'
        }
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(User.objects.count(), 4)  # 3个初始用户 + 1个新用户

    def test_user_login(self):
        """测试用户登录"""
        url = reverse('user-login')
        data = {
            'username': 'reader',
            'password': 'readerpassword'
        }
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertTrue('user' in response.data)

    def test_apply_author(self):
        """测试申请成为作者"""
        # 首先登录读者用户
        self.client.force_authenticate(user=self.reader_user)

        url = reverse('user-apply-author')
        data = {
            'reason': '我想成为作者，发布自己的小说'
        }
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # 验证申请是否创建
        self.assertEqual(AuthorApplication.objects.count(), 1)
        application = AuthorApplication.objects.first()
        self.assertEqual(application.user, self.reader_user)
        self.assertEqual(application.status, 'pending')


class NovelTests(TestCase):
    """小说相关功能测试"""

    def setUp(self):
        """测试前准备工作"""
        self.client = APIClient()

        # 创建测试用户
        self.admin_user = User.objects.create_superuser(
            username='admin',
            email='admin@example.com',
            password='adminpassword'
        )
        self.author_user = User.objects.create_user(
            username='author',
            email='author@example.com',
            password='authorpassword',
            role='author'
        )
        self.reader_user = User.objects.create_user(
            username='reader',
            email='reader@example.com',
            password='readerpassword',
            role='reader'
        )

        # 创建测试分类
        self.category = Category.objects.create(name='测试分类')

        # 创建测试小说
        self.approved_novel = Novel.objects.create(
            title='已审核小说',
            author=self.author_user,
            category=self.category,
            description='这是一本已审核通过的小说',
            status='approved'
        )

        self.pending_novel = Novel.objects.create(
            title='待审核小说',
            author=self.author_user,
            category=self.category,
            description='这是一本待审核的小说',
            status='pending'
        )

        # 创建测试章节
        self.chapter1 = Chapter.objects.create(
            novel=self.approved_novel,
            title='第一章',
            content='这是第一章的内容',
            order=1
        )

        self.chapter2 = Chapter.objects.create(
            novel=self.approved_novel,
            title='第二章',
            content='这是第二章的内容',
            order=2
        )

    def test_list_novels(self):
        """测试获取小说列表"""
        # 读者只能看到已审核的小说
        self.client.force_authenticate(user=self.reader_user)
        url = reverse('novel-list')
        response = self.client.get(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data['results']), 1)  # 只有一本已审核小说

        # 作者可以看到自己的所有小说和其他已审核的小说
        self.client.force_authenticate(user=self.author_user)
        response = self.client.get(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data['results']), 2)  # 两本小说都可见

        # 管理员可以看到所有小说
        self.client.force_authenticate(user=self.admin_user)
        response = self.client.get(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data['results']), 2)  # 两本小说都可见

    def test_create_novel(self):
        """测试创建小说"""
        # 作者可以创建小说
        self.client.force_authenticate(user=self.author_user)
        url = reverse('novel-list')
        data = {
            'title': '新小说',
            'category': self.category.id,
            'description': '这是一本新小说'
        }
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # 验证小说是否创建
        self.assertEqual(Novel.objects.count(), 3)
        novel = Novel.objects.get(title='新小说')
        self.assertEqual(novel.author, self.author_user)
        self.assertEqual(novel.status, 'pending')  # 新创建的小说状态为待审核

        # 读者不能创建小说
        self.client.force_authenticate(user=self.reader_user)
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

    def test_get_novel_detail(self):
        """测试获取小说详情"""
        # 读者可以查看已审核小说
        self.client.force_authenticate(user=self.reader_user)
        url = reverse('novel-detail', args=[self.approved_novel.id])
        response = self.client.get(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['title'], self.approved_novel.title)
        self.assertTrue('chapters' in response.data)
        self.assertEqual(len(response.data['chapters']), 2)  # 两个章节

        # 读者不能查看未审核小说
        url = reverse('novel-detail', args=[self.pending_novel.id])
        response = self.client.get(url)
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

        # 作者可以查看自己的未审核小说
        self.client.force_authenticate(user=self.author_user)
        response = self.client.get(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['title'], self.pending_novel.title)

    def test_search_novels(self):
        """测试搜索小说"""
        self.client.force_authenticate(user=self.reader_user)
        url = reverse('novel-search') + '?q=已审核'
        response = self.client.get(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data['results']), 1)
        self.assertEqual(response.data['results'][0]['title'], self.approved_novel.title)


class BookshelfTests(TestCase):
    """书架功能测试"""

    def setUp(self):
        """测试前准备工作"""
        self.client = APIClient()

        # 创建测试用户
        self.reader_user = User.objects.create_user(
            username='reader',
            email='reader@example.com',
            password='readerpassword',
            role='reader'
        )
        self.author_user = User.objects.create_user(
            username='author',
            email='author@example.com',
            password='authorpassword',
            role='author'
        )

        # 创建测试分类
        self.category = Category.objects.create(name='测试分类')

        # 创建测试小说
        self.novel = Novel.objects.create(
            title='测试小说',
            author=self.author_user,
            category=self.category,
            description='这是一本测试小说',
            status='approved'
        )

        # 创建测试章节
        self.chapter = Chapter.objects.create(
            novel=self.novel,
            title='第一章',
            content='这是第一章的内容',
            order=1
        )

    def test_add_to_bookshelf(self):
        """测试添加小说到书架"""
        self.client.force_authenticate(user=self.reader_user)
        url = reverse('bookshelf-add-to-bookshelf')
        data = {
            'novel_id': self.novel.id
        }
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        # 验证书架记录是否创建
        self.assertEqual(Bookshelf.objects.count(), 1)
        bookshelf = Bookshelf.objects.first()
        self.assertEqual(bookshelf.user, self.reader_user)
        self.assertEqual(bookshelf.novel, self.novel)

    def test_remove_from_bookshelf(self):
        """测试从书架中移除小说"""
        # 先添加到书架
        Bookshelf.objects.create(
            user=self.reader_user,
            novel=self.novel
        )

        self.client.force_authenticate(user=self.reader_user)
        url = reverse('bookshelf-remove-from-bookshelf')
        data = {
            'novel_id': self.novel.id
        }
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        # 验证书架记录是否删除
        self.assertEqual(Bookshelf.objects.count(), 0)

    def test_read_chapter(self):
        """测试阅读章节并更新阅读进度"""
        self.client.force_authenticate(user=self.reader_user)
        url = reverse('chapter-read', args=[self.chapter.id])
        response = self.client.post(url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        # 验证书架记录是否正确更新
        self.assertEqual(Bookshelf.objects.count(), 1)
        bookshelf = Bookshelf.objects.first()
        self.assertEqual(bookshelf.user, self.reader_user)
        self.assertEqual(bookshelf.novel, self.novel)
        self.assertEqual(bookshelf.last_read_chapter, self.chapter)


class AdminTests(TestCase):
    """管理员功能测试"""

    def setUp(self):
        """测试前准备工作"""
        self.client = APIClient()

        # 创建测试用户
        self.admin_user = User.objects.create_superuser(
            username='admin',
            email='admin@example.com',
            password='adminpassword'
        )
        self.reader_user = User.objects.create_user(
            username='reader',
            email='reader@example.com',
            password='readerpassword',
            role='reader'
        )
        self.author_user = User.objects.create_user(
            username='author',
            email='author@example.com',
            password='authorpassword',
            role='author'
        )

        # 创建测试分类
        self.category = Category.objects.create(name='测试分类')

        # 创建测试小说
        self.pending_novel = Novel.objects.create(
            title='待审核小说',
            author=self.author_user,
            category=self.category,
            description='这是一本待审核的小说',
            status='pending'
        )

        # 创建测试作者申请
        self.author_application = AuthorApplication.objects.create(
            user=self.reader_user,
            reason='我想成为作者',
            status='pending'
        )

    def test_process_author_application(self):
        """测试处理作者申请"""
        self.client.force_authenticate(user=self.admin_user)
        url = reverse('admin-process-author-application', args=[self.author_application.id])
        data = {
            'action': 'approve',
            'admin_notes': '通过申请'
        }
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        # 验证申请状态是否更新
        self.author_application.refresh_from_db()
        self.assertEqual(self.author_application.status, 'approved')
        self.assertIsNotNone(self.author_application.processed_at)
        self.assertEqual(self.author_application.admin_notes, '通过申请')

        # 验证用户角色是否更新
        self.reader_user.refresh_from_db()
        self.assertEqual(self.reader_user.role, 'author')

    def test_process_novel(self):
        """测试审核小说"""
        self.client.force_authenticate(user=self.admin_user)
        url = reverse('admin-process-novel', args=[self.pending_novel.id])
        data = {
            'action': 'approve',
            'feedback': '小说内容符合要求，通过审核'
        }
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        # 验证小说状态是否更新
        self.pending_novel.refresh_from_db()
        self.assertEqual(self.pending_novel.status, 'approved')

    def test_category_management(self):
        """测试分类管理"""
        self.client.force_authenticate(user=self.admin_user)

        # 创建分类
        url = reverse('admin-create-category')
        data = {
            'name': '新分类'
        }
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(Category.objects.count(), 2)

        # 更新分类
        new_category = Category.objects.get(name='新分类')
        url = reverse('admin-update-category', args=[new_category.id])
        data = {
            'name': '更新后的分类'
        }
        response = self.client.put(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        new_category.refresh_from_db()
        self.assertEqual(new_category.name, '更新后的分类')

        # 删除分类
        url = reverse('admin-delete-category', args=[new_category.id])
        response = self.client.delete(url)
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.assertEqual(Category.objects.count(), 1)
